import grails.util.Environment
import org.grailsext.annotation.Privileged
import java.lang.reflect.Field
import java.util.Collections
import org.apache.commons.collections.CollectionUtils

/**
 * Base class for all Controllers
 * 
 * @author yuxing
 *
 */
abstract class BaseController {

	/**
	 * Authentication interception method for all access.
	 * @return return true if authentication success.
	 */
	def auth(){
		
		if(Environment.current == Environment.DEVELOPMENT) {
			println "All actions are privileged in Development mode"
			return true
		}
		
		println "Start to check user login: ${session.userId}"
		if(!session.userId){
			println "User not login"
			def originalRequestParams = [controller:controllerName, action:actionName]
			originalRequestParams.putAll(params)
			session.originalRequestParams = originalRequestParams
			flash.message = "${message(code: 'user.auth.login.require.message', default:'You must login first')}"
			redirect(controller:'user', action:'login')
			return false
		}
		println "Action Name: " + actionName

		// 'admin' user is the super power.
		if(session.userName != null && session.userName == 'admin'){
			println "You have super power!"
			return true
		}

		// Loop to check all Action closures
		for (Field field : this.getClass().getDeclaredFields()) {
			// Find matched Action
			if (field.getName().equals(actionName)) {
				Privileged annoPriv = (Privileged)field.getAnnotation(Privileged.class)
				if(annoPriv == null){
					println "No annotation for action " + field.getName()
					continue
				}

				// loop to find all privileges assigned to user
				def user = User.get(session.userId)
				def privileges = new HashSet()//Privilege should be unique
				for(Role r : user.roles){
					println "User has role: ${r.roleName}"
					CollectionUtils.addAll(privileges, r.privileges.iterator())
//					privileges.add(r.privileges)
				}
				println "User has privileges ${privileges}}"

				String[] requiredPrivileges = annoPriv.privileges()
				// loop to check whether privileged
				boolean isPrivileged = false
				for (String s : requiredPrivileges) {
					for(Privilege p : privileges){
						println "${p.privName} == ${s.trim()}"
						if(p.privName == s.trim()){
							isPrivileged = true
						}
					}
				}
				if(isPrivileged == false){
					println "Access denied, privilege ${requiredPrivileges} required"
					def msg = 'You are not allowed to access this page, please login with other ID or contact IT.'
					flash.message = "${message(code:'user.auth.not.alowed.message', default:msg)}"
					redirect(controller:"user", action:"login")
					return false
				}
				break// break for found the closure
			}
		}
		println "Authentication completed!"
	}

	/**
	 * Closure to redirect un-privileged access.
	 * TODO It doesn't work.
	 */
	def accessDenied = {
		println "Redirect to user login page"
		redirect(controller:"user", action:"login")
//		render(view:'user/login')
	}

	protected boolean saveEntity(entity){
		if(entity.hasErrors()){
			println "Entity ${entity} has errors"
			entity.errors.allErrors.each{
				println it
			}
			flash.message = entity.errors
			return false
		} else {
			if(!entity.save(flush:true)){
				println "Save entity ${entity} with errors"
				entity.errors.allErrors.each{
					println it
					flash.message = entity.errors
				}
				return false
			}
			return true
		}
	}
}
